 

import '@material/web/all.js';
import { infoUtil } from "./util/infoUtil";
import { file, fileInfoBaseDto, folder, fileTransferApi} from "ispace.core.main"
import { UploadFileDto } from './dto/uploadFileDto';

console.log("file upload Page");

 let fileHandler = {
    set(target: any, prop: string, value: any) {
    target[prop] = value;

    // step init:
    let fileElement = document.getElementById(`file-${target.id}`);
    if(!fileElement){
        return true;
    }

    // step 1: 更新数据 
    let fileData = target;
       fileElement.innerHTML = randerItem(fileData);
    

    // step 2: 更新进度
    let progressElement = document.getElementById(`progress`)! as HTMLProgressElement; 
    progressElement.value = getProgress();

    
    return true;
  },
}

class Program {

    // 是否上传中
     private _isUploading = false;
     public get isUploading() {
         return this._isUploading;
     }
     public set isUploading(value) {
         this._isUploading = value;

         // 禁用上传按钮
         let submitElement = document.getElementById("submit")! as HTMLButtonElement;
         submitElement.disabled = value;

         // 整体进度状态
         let progressElement = document.getElementById("progress")!;
         progressElement.style.display = value?"block":"none";
     }

     // 当前文件夹
     private _currentDir = "";
    get currentDir() {
         return this._currentDir;
     }
    set currentDir(value) {
         this._currentDir = value;
     }
 
     // 清单列表
     private _fileList:UploadFileDto[] = [];
    get fileList() {
         return this._fileList;
    }
    set fileList(value) {
         this._fileList = value;

         // step init:
        let fileListElement = document.getElementById("fileList")!
        if(this._fileList.length>0){
            fileListElement.style.display = "block"; 
        }
        else{
            fileListElement.style.display = "none";
        }
         // step 1: 清除数据
        let dataItems = fileListElement.getElementsByClassName("data-item");
        let count = dataItems.length;
        if(count > 0){
            for(let i=0; i < count; i++){
                fileListElement.removeChild(dataItems[0]);
            }
        }
       
         // step 2： 渲染数据
         for(let i=0; i < this.fileList.length; i++){
             let fileData = this.fileList[i];
             let fileElement = document.createElement("md-list-item");
             fileElement.id = `file-${fileData.id}`;
             fileElement.classList.add("data-item");
             fileElement.innerHTML =randerItem(fileData);
             fileListElement.appendChild(fileElement); 
         } 
    }
    addFile(fileData:UploadFileDto) {
         this.fileList.push(fileData);

         // step init:
        let fileListElement = document.getElementById("fileList")! 
         if(this._fileList.length>0){
            fileListElement.style.display = "block"; 
            fileListElement.parentElement!.style.display = "block"; 
        }
        else{
            fileListElement.style.display = "none";
            fileListElement.parentElement!.style.display = "none";
        }
         // step 1：渲染
            let fileElement = document.createElement("md-list-item");
            fileElement.id = `file-${fileData.id}`;
            fileElement.classList.add("data-item");
            fileElement.innerHTML = randerItem(fileData);
            fileListElement.appendChild(fileElement); 
    }
    
     // 入口
    async main(){  
        
        const params = new URLSearchParams(window.location.search);
        this.currentDir = params.get("path")??""; 
        if((this.currentDir?.length??0) == 0)
        {
            infoUtil.displayErrorInfo("文件夹地址不可空！"); 
            return;
        }
 
        // step 1: 获取文件内容
        const fileInfo = await folder.statf(this.currentDir!).toPromise();
        if(fileInfo == null)
        {
            infoUtil.displayErrorInfo("文件不存在或不可访问！");
            return;
        }

        // step 2： core  
        // step 2.1: 展示文件内容
        await this.displayFileInfo(fileInfo!);  

        // step 2.2: 事件绑定
        document.getElementById("uploadFile")!.onclick = async () => {
            let inputElement = document.createElement("input");
            inputElement.type = "file";
            inputElement.multiple = true; ;
            inputElement.onchange = async (e) => {
                let files = inputElement.files;
                if(files == null || files.length == 0) {
                    return;
                }
                for(let i = 0; i < files.length; i++) {
                    let file = files[i];
                    let data:UploadFileDto = new Proxy<UploadFileDto>({
                        id: file.name,
                        name: file.name,
                        size: file.size,
                        file: file,
                        progress: 0,
                        status: 'waiting',
                        path: file.name
                    },fileHandler
                    );
                    this.addFile(data); 
                }
            }
            inputElement.click(); 
        }

        document.getElementById("uploadFolder")!.onclick = async () => {
            let inputElement = document.createElement("input");
            inputElement.type = "file";
            inputElement.webkitdirectory = true;
            inputElement.multiple = true; ;
            inputElement.onchange = async (e) => {
                let files = inputElement.files;
                if(files == null || files.length == 0) {
                    return;
                }
                for(let i = 0; i < files.length; i++) {
                    let file = files[i];
                    let data:UploadFileDto = new Proxy<UploadFileDto>({
                        id: file.webkitRelativePath,
                        name: file.name,
                        size: file.size,
                        file: file,
                        progress: 0,
                        status:"waiting",
                        path: file.webkitRelativePath
                    },fileHandler
                    );
                    this.addFile(data); 
                } 
            }
            inputElement.click();
        }     
        
        document.getElementById("submit")!.onclick = async () => {
            infoUtil.displayErrorInfo("");
            await this.upload();
        }

        let that = this;
        document.getElementById("fileList")!.addEventListener('click', function(e:any) {
            // 检查点击目标是否包含rmItem类
            if (e.target?.classList?.contains('rmItem')) {  
                let id = e.target.getAttribute("data-id");  
                that.fileList = that.fileList.filter((item) => item.id !== id);
              }
            }); 
    }
 
    // 上传文件
    async upload() {
        // step check:
        if(this.isUploading) {
            infoUtil.displayErrorInfo("正在上传，请稍后重试！");
            return;
        }
        this.isUploading = true;  

        // step core:
        try{
            // step 1: 获取清单列表
            if(this.fileList.length == 0) {
                infoUtil.displayErrorInfo("请选择文件或文件夹！");
                this.isUploading = true;  
                return;
            }

            // step 2： 遍历处理清单信息
            // step 3： 获取所有文件夹，并上传
            // step 4： 获取所有文件，并上传
            for(let i = 0; i < this.fileList.length; i++) {
                let fileData = this.fileList[i]; 
                if(fileData.status == "success") {
                    continue;
                }
                fileData.status = "uploading";
                const result = await this.uploadFile(fileData);
                if(!result) {
                    infoUtil.displayErrorInfo("上传文件失败！文件名："+fileData.name);
                    fileData.status = "error";
                    this.isUploading = true;  
                    return;
                } 
                fileData.status = "success";
            } 

            // step 3： 标记上传完成
            this.isUploading = true;  

            return true;
        }
        catch(e: any){ 
            infoUtil.displayErrorInfo("上传异常："+e.message);
        }
        finally{
            this.isUploading = false; 
        }  
    }

    // 上传文件
    async uploadFile(data: UploadFileDto):Promise<boolean>  { 
 
        if(data.size<= 1024*1024*100) {
            // step 1: 上传文件 
         let result = await fileTransferApi.fileUpload(this.currentDir+"/"+data.path, data.file,
            (progressEvent)=>{
            const percentCompleted = 
                (progressEvent.loaded ) / ((progressEvent.total ?? 1))
            ;
            data.progress = percentCompleted; 
        }
        ).toPromise();

        if(result == null) {
            infoUtil.displayErrorInfo("上传文件失败！文件名："+data.name);
            return false;
        }
            return true;
        }
        
        // step 2: 大文件上传
        let key = null;
        try{
        // step 2.1: init
        let result = await fileTransferApi.bigFileUploadInit(data.file.size).toPromise();
        if(result == null || result.data == null || result.data.key == null) {
            infoUtil.displayErrorInfo("上传文件失败！文件名："+data.name);
            return false; 
        }
        // step 2.2: 分片上传  
        key = result.data.key;
        let i = 0;
        for(let size = 0; size < data.file.size; size += result.data.chunkSize) {
            let end = size + result.data.chunkSize;
            if(end > data.file.size) {
                end = data.file.size;
            }
           let chunkResult = await fileTransferApi.bigFileUploadChunk(result?.data!.key,i,data.file.slice(size,end)).toPromise();
           if(chunkResult == null) {
               infoUtil.displayErrorInfo("上传文件失败！文件名："+data.name);
                await fileTransferApi.bigFileUploadCancel(result?.data!.key).toPromise();
               return false;
           }    
           i++;
           if(data.file.size>0){
           data.progress = size/data.file.size;
           }
        }

        // step 2.3: 合并文件
        let completeResult = await fileTransferApi.bigFileUploadComplete(
            result?.data!.key,
            data.name,data.file.size,result.data.chunkSize,result.data.chunkCount,
            this.currentDir+"/"+data.path,0
        ).toPromise();
        if(completeResult == null) {
            infoUtil.displayErrorInfo("上传文件失败！文件名："+data.name);
                await fileTransferApi.bigFileUploadCancel(result?.data!.key).toPromise();
            return false;
        }
        
        return true;
    }catch(e: any){
        infoUtil.displayErrorInfo("上传文件失败！文件名："+data.name);
        if(key != null) {
         await fileTransferApi.bigFileUploadCancel(key).toPromise();
        }
        return false;
    }
    }
 
    // 展示文件内容
    async displayFileInfo(fileInfo:fileInfoBaseDto){ 
        // const currentDirElement = document.getElementById("currentDir")! as HTMLDivElement;
        // currentDirElement.innerHTML = fileInfo.path??""; 
    }
}

let  p =new Program();
p.main();

function getProgress() {
    let total = 0;
    let index = 0;
    p.fileList.forEach(file => {
        total += file.size??0;
        index += (file.progress??0)*(file.size??0);
    });

    if(total == 0) {
        return 0;
    }

    return index/total;
}

function randerItem(fileData:UploadFileDto):string {
    return `<div class="data-item-content">
                    <span>${fileData.name}</span>
                    <span>${ infoUtil.formatFileSize(fileData.size)} </span>
                    <span>${fileData.status == "uploading"?(
                        '<md-circular-progress  value="'+fileData.progress+'"></md-circular-progress>'
                    ): infoUtil.convertStatus(fileData.status)}</span>
                    <span class="rmItem" data-id="${fileData.id}">移除</span>
                    </div>`;
}
 